﻿using Mapster;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Query;
using System.Linq.Expressions;
using Yz.Base;
using Yz.DB.EFCore.DBUtility;
namespace Yz.DB.EFCore.Extensions
{
    public static class AccessExtension
    {
        #region 新增
        /// <summary>
        /// 新增
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="db"></param>
        /// <param name="model"></param>
        /// <param name="where"></param>
        /// <returns></returns>
        public static ReturnCode Add<TEntity>(this DbContext db, TEntity model, Expression<Func<TEntity, bool>> where = null) where TEntity : BaseEntity
        {
            if (where != null && db.Set<TEntity>().AsNoTracking().Where(where).Any())
            {
                return ReturnCode.Exit;
            }
            db.Set<TEntity>().Add(model);
            if (db.SaveChanges() > 0)
            {
                return ReturnCode.Success;
            }
            return ReturnCode.Fail;
        }
        /// <summary>
        /// 新增
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="db"></param>
        /// <param name="model"></param>
        /// <param name="where"></param>
        /// <returns></returns>
        public static async Task<ReturnCode> AddAsync<TEntity>(this DbContext db, TEntity model, Expression<Func<TEntity, bool>> where = null) where TEntity : BaseEntity
        {
            if (where != null && await db.Set<TEntity>().AsNoTracking().Where(where).AnyAsync())
            {
                return ReturnCode.Exit;
            }
            db.Set<TEntity>().Add(model);
            if (await db.SaveChangesAsync() > 0)
            {
                return ReturnCode.Success;
            }
            return ReturnCode.Fail;
        }
        /// <summary>
        /// 新增(大于一个条件时)
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="db"></param>
        /// <param name="model"></param>
        /// <param name="whereList"></param>
        /// <returns></returns>
        public static ReturnCode Add<TEntity>(this DbContext db, TEntity model, List<Expression<Func<TEntity, bool>>> whereList) where TEntity : BaseEntity
        {
            if (whereList == null || whereList.Count == 0)
            {
                return Add(db, model);
            }
            IQueryable<TEntity> list = db.Set<TEntity>().AsNoTracking().Where(whereList[0]);
            foreach (var item in whereList.Skip(1).ToList())
            {
                list = list.Union(db.Set<TEntity>().AsNoTracking().Where(item));
            }
            if (list.Any())
            {
                return ReturnCode.Exit;
            }
            db.Set<TEntity>().Add(model);
            if (db.SaveChanges() > 0)
            {
                return ReturnCode.Success;
            }
            return ReturnCode.Fail;
        }
        /// <summary>
        /// 新增(大于一个条件时)
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="db"></param>
        /// <param name="model"></param>
        /// <param name="whereList"></param>
        /// <returns></returns>
        public static async Task<ReturnCode> AddAsync<TEntity>(this DbContext db, TEntity model, List<Expression<Func<TEntity, bool>>> whereList) where TEntity : BaseEntity
        {
            if (whereList == null || whereList.Count == 0)
            {
                return await AddAsync(db, model);
            }
            IQueryable<TEntity> list = db.Set<TEntity>().AsNoTracking().Where(whereList[0]);
            foreach (var item in whereList.Skip(1).ToList())
            {
                list = list.Union(db.Set<TEntity>().AsNoTracking().Where(item));
            }
            if (await list.AnyAsync())
            {
                return ReturnCode.Exit;
            }
            db.Set<TEntity>().Add(model);
            if (await db.SaveChangesAsync() > 0)
            {
                return ReturnCode.Success;
            }
            return ReturnCode.Fail;
        }
        /// <summary>
        /// 新增并返回新增后的值
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="db"></param>
        /// <param name="model"></param>
        /// <param name="where"></param>
        /// <returns></returns>
        public static TEntity AddGet<TEntity>(this DbContext db, TEntity model, Expression<Func<TEntity, bool>> where = null) where TEntity : BaseEntity
        {
            if (where != null && db.Set<TEntity>().AsNoTracking().Where(where).Any())
            {
                return null;
            }
            db.Set<TEntity>().Add(model);
            if (db.SaveChanges() > 0)
            {
                return model;
            }
            return model;
        }
        /// <summary>
        /// 新增并返回新增后的值
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="db"></param>
        /// <param name="model"></param>
        /// <param name="where"></param>
        /// <returns></returns>
        public static async Task<TEntity> AddGetAsync<TEntity>(this DbContext db, TEntity model, Expression<Func<TEntity, bool>> where = null) where TEntity : BaseEntity
        {
            if (where != null && await db.Set<TEntity>().AsNoTracking().Where(where).AnyAsync())
            {
                return null;
            }
            db.Set<TEntity>().Add(model);
            if (await db.SaveChangesAsync() > 0)
            {
                return model;
            }
            return model;
        }
        /// <summary>
        /// 新增并返回新增后的值
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="db"></param>
        /// <param name="model"></param>
        /// <param name="whereList"></param>
        /// <returns></returns>
        public static TEntity AddGet<TEntity>(this DbContext db, TEntity model, List<Expression<Func<TEntity, bool>>> whereList) where TEntity : BaseEntity
        {
            if (whereList == null || whereList.Count == 0)
            {
                return db.AddGet(model);
            }
            IQueryable<TEntity> list = db.Set<TEntity>().AsNoTracking().Where(whereList[0]);
            foreach (var item in whereList.Skip(1).ToList())
            {
                list = list.Union(db.Set<TEntity>().AsNoTracking().Where(item));
            }
            if (list.Any())
            {
                return null;
            }
            db.Set<TEntity>().Add(model);
            if (db.SaveChanges() > 0)
            {
                return model;
            }
            return model;
        }
        /// <summary>
        /// 新增并返回新增后的值
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="db"></param>
        /// <param name="model"></param>
        /// <param name="whereList"></param>
        /// <returns></returns>
        public static async Task<TEntity> AddGetAsync<TEntity>(this DbContext db, TEntity model, List<Expression<Func<TEntity, bool>>> whereList) where TEntity : BaseEntity
        {
            if (whereList == null || whereList.Count == 0)
            {
                return await db.AddGetAsync(model);
            }
            IQueryable<TEntity> list = db.Set<TEntity>().AsNoTracking().Where(whereList[0]);
            foreach (var item in whereList.Skip(1).ToList())
            {
                list = list.Union(db.Set<TEntity>().AsNoTracking().Where(item));
            }
            if (await list.AnyAsync())
            {
                return null;
            }
            db.Set<TEntity>().Add(model);
            if (await db.SaveChangesAsync() > 0)
            {
                return model;
            }
            return model;
        }
        /// <summary>
        /// 批量新增
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="db"></param>
        /// <param name="modelList"></param>
        /// <returns></returns>
        public static int BatchAdd<TEntity>(this DbContext db, List<TEntity> modelList) where TEntity : BaseEntity
        {
            if (modelList == null || modelList.Count == 0)
            {
                return -1;
            }
            int count;
            if (db.Database.IsSqlServer())
            {
                count = modelList.BulkInsertSqlServer(db);
            }
            else
            {
                count = modelList.BulkInsertMySql(db);
            }
            return count;
        }
        /// <summary>
        /// 批量新增
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="db"></param>
        /// <param name="modelList"></param>
        /// <returns></returns>
        public static async Task<int> BatchAddAsync<TEntity>(this DbContext db, List<TEntity> modelList) where TEntity : BaseEntity
        {
            if (modelList == null || modelList.Count == 0)
            {
                return -1;
            }
            int count;
            if (db.Database.IsSqlServer())
            {
                count = await modelList.BulkInsertSqlServerAsync(db);
            }
            else
            {
                count = await modelList.BulkInsertMySqlAsync(db);
            }
            return count;
        }
        #endregion

        #region 修改
        /// <summary>
        /// 单条更新
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="db"></param>
        /// <param name="epsUpdate"></param>
        /// <param name="where1">判断要更新的原始数据是否存在</param>
        /// <param name="where2">判断更新的数据是否重复</param>
        /// <returns></returns>
        public static ReturnCode Update<TEntity>(this DbContext db, Expression<Func<SetPropertyCalls<TEntity>, SetPropertyCalls<TEntity>>> setPropertyCalls, Expression<Func<TEntity, bool>> where1 = null, Expression<Func<TEntity, bool>> where2 = null) where TEntity : BaseEntity
        {
            if (where1 != null && !db.Set<TEntity>().AsNoTracking().Where(where1).Any())
            {
                return ReturnCode.NoExit;
            }
            if (where2 != null && db.Set<TEntity>().AsNoTracking().Where(where2).Any())
            {
                return ReturnCode.Exit;
            }
            if (db.Set<TEntity>().Where(where1).ExecuteUpdate(setPropertyCalls) > 0)
            {
                return ReturnCode.Success;
            }
            return ReturnCode.Fail;
        }
        /// <summary>
        /// 单条更新
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="db"></param>
        /// <param name="epsUpdate"></param>
        /// <param name="where1">判断要更新的原始数据是否存在</param>
        /// <param name="where2">判断更新的数据是否重复</param>
        /// <returns></returns>
        public static async Task<ReturnCode> UpdateAsync<TEntity>(this DbContext db, Expression<Func<SetPropertyCalls<TEntity>, SetPropertyCalls<TEntity>>> setPropertyCalls, Expression<Func<TEntity, bool>> where1 = null, Expression<Func<TEntity, bool>> where2 = null) where TEntity : BaseEntity
        {
            if (where1 != null && await db.Set<TEntity>().AsNoTracking().Where(where1).AnyAsync() == false)
            {
                return ReturnCode.NoExit;
            }
            if (where2 != null && await db.Set<TEntity>().AsNoTracking().Where(where2).AnyAsync())
            {
                return ReturnCode.Exit;
            }

            if (await db.Set<TEntity>().Where(where1).ExecuteUpdateAsync(setPropertyCalls) > 0)
            {
                return ReturnCode.Success;
            }
            return ReturnCode.Fail;
        }
        /// <summary>
        /// 修改
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="db"></param>
        /// <param name="epsUpdate"></param>
        /// <param name="whereList2">判断更新的数据是否重复</param>
        /// <param name="where1">判断要更新的原始数据是否存在</param>
        /// <returns></returns>
        public static ReturnCode Update<TEntity>(this DbContext db, Expression<Func<SetPropertyCalls<TEntity>, SetPropertyCalls<TEntity>>> setPropertyCalls, List<Expression<Func<TEntity, bool>>> whereList2, Expression<Func<TEntity, bool>> where1 = null) where TEntity : BaseEntity
        {
            if (whereList2 == null || whereList2.Count == 0)
            {
                return db.Update(setPropertyCalls, where1);
            }
            if (where1 != null && !db.Set<TEntity>().AsNoTracking().Where(where1).Any())
            {
                return ReturnCode.NoExit;
            }
            IQueryable<TEntity> list = db.Set<TEntity>().AsNoTracking().Where(whereList2[0]);
            foreach (var item in whereList2.Skip(1).ToList())
            {
                list = list.Union(db.Set<TEntity>().AsNoTracking().Where(item));
            }
            if (list.Any())
            {
                return ReturnCode.Exit;
            }
            if (db.Set<TEntity>().Where(where1).ExecuteUpdate(setPropertyCalls) > 0)
            {
                return ReturnCode.Success;
            }
            return ReturnCode.Fail;
        }
        /// <summary>
        /// 修改
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="db"></param>
        /// <param name="epsUpdate"></param>
        /// <param name="whereList2">判断更新的数据是否重复</param>
        /// <param name="where1">判断要更新的原始数据是否存在</param>
        /// <returns></returns>
        public static async Task<ReturnCode> UpdateAsync<TEntity>(this DbContext db, Expression<Func<SetPropertyCalls<TEntity>, SetPropertyCalls<TEntity>>> setPropertyCalls, List<Expression<Func<TEntity, bool>>> whereList2, Expression<Func<TEntity, bool>> where1 = null) where TEntity : BaseEntity
        {
            if (whereList2 == null || whereList2.Count == 0)
            {
                return await db.UpdateAsync(setPropertyCalls, where1);
            }
            if (where1 != null && await db.Set<TEntity>().AsNoTracking().Where(where1).AnyAsync() == false)
            {
                return ReturnCode.NoExit;
            }
            IQueryable<TEntity> list = db.Set<TEntity>().AsNoTracking().Where(whereList2[0]);
            foreach (var item in whereList2.Skip(1).ToList())
            {
                list = list.Union(db.Set<TEntity>().AsNoTracking().Where(item));
            }
            if (await list.AnyAsync())
            {
                return ReturnCode.Exit;
            }
            if (await db.Set<TEntity>().Where(where1).ExecuteUpdateAsync(setPropertyCalls) > 0)
            {
                return ReturnCode.Success;
            }
            return ReturnCode.Fail;
        }
        /// <summary>
        /// 批量更新对象（需要更新的内容不一样）
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="db"></param>
        /// <param name="epsUpdate"></param>
        /// <param name="modelList"></param>
        /// <returns></returns>
        public static int BatchUpdate<TEntity>(this DbContext db, Expression<Func<TEntity, TEntity>> epsUpdate, List<TEntity> modelList) where TEntity : BaseEntity
        {
            int count;
            if (db.Database.IsSqlServer())
            {
                count = modelList.BulkUpdateSqlServer(db, epsUpdate);
            }
            else
            {
                count = modelList.BulkUpdateMySql(db, epsUpdate);
            }
            return count;
        }
        /// <summary>
        /// 批量更新对象（需要更新的内容不一样）
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="db"></param>
        /// <param name="epsUpdate"></param>
        /// <param name="modelList"></param>
        /// <returns></returns>
        public static async Task<int> BatchUpdateAsync<TEntity>(this DbContext db, Expression<Func<TEntity, TEntity>> epsUpdate, List<TEntity> modelList) where TEntity : BaseEntity
        {
            int count = 0;
            if (db.Database.IsSqlServer())
            {
                count = await modelList.BulkUpdateSqlServerAsync(db, epsUpdate);
            }
            else
            {
                count = await modelList.BulkUpdateMySqlAsync(db, epsUpdate);
            }
            return count;
        }
        /// <summary>
        /// 批量更新
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="db"></param>
        /// <param name="epsUpdate"></param>
        /// <param name="where"></param>
        /// <returns></returns>
        public static int BatchUpdate<TEntity>(this DbContext db, Expression<Func<SetPropertyCalls<TEntity>, SetPropertyCalls<TEntity>>> setPropertyCalls, Expression<Func<TEntity, bool>> where = null) where TEntity : BaseEntity
        {
            if (where != null)
            {
                return db.Set<TEntity>().Where(where).ExecuteUpdate(setPropertyCalls);
            }
            return db.Set<TEntity>().ExecuteUpdate(setPropertyCalls);
        }
        /// <summary>
        /// 批量更新
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="db"></param>
        /// <param name="epsUpdate"></param>
        /// <param name="where"></param>
        /// <returns></returns>
        public static async Task<int> BatchUpdateAsync<TEntity>(this DbContext db, Expression<Func<SetPropertyCalls<TEntity>, SetPropertyCalls<TEntity>>> setPropertyCalls, Expression<Func<TEntity, bool>> where = null) where TEntity : BaseEntity
        {
            if (where != null)
            {
                return await db.Set<TEntity>().Where(where).ExecuteUpdateAsync(setPropertyCalls);
            }
            return await db.Set<TEntity>().ExecuteUpdateAsync(setPropertyCalls);
        }
        #endregion

        #region 删除
        /// <summary>
        /// 单条删除
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="db"></param>
        /// <param name="where"></param>
        /// <returns></returns>
        public static ReturnCode Delete<TEntity>(this DbContext db, Expression<Func<TEntity, bool>> where) where TEntity : BaseEntity
        {
            if (where == null || !db.Set<TEntity>().Where(where).Any())
            {
                return ReturnCode.NoExit;
            }
            int count = db.Set<TEntity>().Where(where).ExecuteDelete();
            if (count > 0)
            {
                return ReturnCode.Success;
            }
            return ReturnCode.Fail;
        }
        /// <summary>
        /// 单条删除
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="db"></param>
        /// <param name="where"></param>
        /// <returns></returns>
        public static async Task<ReturnCode> DeleteAsync<TEntity>(this DbContext db, Expression<Func<TEntity, bool>> where) where TEntity : BaseEntity
        {
            if (where == null || await db.Set<TEntity>().Where(where).AnyAsync() == false)
            {
                return ReturnCode.NoExit;
            }
            int count = await db.Set<TEntity>().Where(where).ExecuteDeleteAsync();
            if (count > 0)
            {
                return ReturnCode.Success;
            }
            return ReturnCode.Fail;
        }
        /// <summary>
        /// 批量删除
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="db"></param>
        /// <param name="where"></param>
        /// <returns></returns>
        public static int BatchDelete<TEntity>(this DbContext db, Expression<Func<TEntity, bool>> where = null) where TEntity : BaseEntity
        {
            if (where != null)
            {
                return db.Set<TEntity>().Where(where).ExecuteDelete();///适配批量删除  
            }
            return db.Set<TEntity>().ExecuteDelete();///适配批量删除 
        }
        /// <summary>
        /// 批量删除
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="db"></param>
        /// <param name="where"></param>
        /// <returns></returns>
        public static async Task<int> BatchDeleteAsync<TEntity>(this DbContext db, Expression<Func<TEntity, bool>> where = null) where TEntity : BaseEntity
        {
            if (where != null)
            {
                return await db.Set<TEntity>().Where(where).ExecuteDeleteAsync();///适配批量删除  
            }
            return await db.Set<TEntity>().ExecuteDeleteAsync();///适配批量删除 
        }
        #endregion

        #region 查询
        /// <summary>
        /// 根据条件查询返回IQueryable<TEntity>
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="db"></param>
        /// <param name="where"></param>
        /// <returns></returns>
        public static IQueryable<TEntity> GetQueryable<TEntity>(this DbContext db, Expression<Func<TEntity, bool>> where) where TEntity : BaseEntity
        {
            return db.Set<TEntity>().AsNoTracking().Where(where);
        }

        /// <summary>
        /// 根据条件判断是否存在
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="db"></param>
        /// <param name="where"></param>
        /// <returns></returns>

        public static bool IsExist<TEntity>(this DbContext db, Expression<Func<TEntity, bool>> where = null) where TEntity : BaseEntity
        {
            if (where != null)
            {
                return db.Set<TEntity>().AsNoTracking().Where(where).Any();
            }
            return db.Set<TEntity>().AsNoTracking().Any();
        }
        /// <summary>
        /// 根据提偶见判断是否存在（异步）
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="db"></param>
        /// <param name="where"></param>
        /// <returns></returns>
        public static async Task<bool> IsExistAsync<TEntity>(this DbContext db, Expression<Func<TEntity, bool>> where = null) where TEntity : BaseEntity
        {
            if (where != null)
            {
                return await db.Set<TEntity>().AsNoTracking().Where(where).AnyAsync();
            }
            return await db.Set<TEntity>().AsNoTracking().AnyAsync();
        }
        /// <summary>
        /// 根据条件获得所有数量
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="db"></param>
        /// <param name="where"></param>
        /// <returns></returns>
        public static int GetTotal<TEntity>(this DbContext db, Expression<Func<TEntity, bool>> where = null) where TEntity : BaseEntity
        {
            if (where != null)
            {
                return db.Set<TEntity>().AsNoTracking().Where(where).Count();
            }
            return db.Set<TEntity>().AsNoTracking().Count();
        }
        /// <summary>
        /// 根据条件获得所有数量
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="db"></param>
        /// <param name="where"></param>
        /// <returns></returns>
        public static async Task<int> GetTotalAsync<TEntity>(this DbContext db, Expression<Func<TEntity, bool>> where = null) where TEntity : BaseEntity
        {
            if (where != null)
            {
                return await db.Set<TEntity>().AsNoTracking().Where(where).CountAsync();
            }
            return await db.Set<TEntity>().AsNoTracking().CountAsync();
        }
        /// <summary>
        /// 根据条件获得所有数量（如果条件中出现or 改为调用此方法，把or拆成多个条件）
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="db"></param>
        /// <param name="whereList"></param>
        /// <returns></returns>
        public static int GetUnionTotal<TEntity>(this DbContext db, List<Expression<Func<TEntity, bool>>> whereList) where TEntity : BaseEntity
        {
            if (whereList == null || whereList.Count == 0)
            {
                return db.GetTotal<TEntity>();
            }
            IQueryable<int> listCount = db.Set<TEntity>().AsNoTracking().Where(whereList[0]).Select(p => p.Id);
            foreach (var item in whereList.Skip(1).ToList())
            {
                listCount = listCount.Union(db.Set<TEntity>().AsNoTracking().Where(item).Select(p => p.Id));
            }
            return listCount.Count();
        }
        /// <summary>
        /// 根据条件获得所有数量（如果条件中出现or 改为调用此方法，把or拆成多个条件）
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="db"></param>
        /// <param name="whereList"></param>
        /// <returns></returns>
        public static async Task<int> GetUnionTotalAsync<TEntity>(this DbContext db, List<Expression<Func<TEntity, bool>>> whereList) where TEntity : BaseEntity
        {
            if (whereList == null || whereList.Count == 0)
            {
                return await db.GetTotalAsync<TEntity>();
            }
            IQueryable<int> listCount = db.Set<TEntity>().AsNoTracking().Where(whereList[0]).Select(p => p.Id);
            foreach (var item in whereList.Skip(1).ToList())
            {
                listCount = listCount.Union(db.Set<TEntity>().AsNoTracking().Where(item).Select(p => p.Id));
            }
            return await listCount.CountAsync();
        }
        /// <summary>
        /// 根据条件获得model
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="db"></param>

        /// <param name="where"></param>
        /// <returns></returns>
        public static T GetModel<TEntity, T>(this DbContext db, Expression<Func<TEntity, bool>> where = null, List<ParaOrder<TEntity>> orders = null) where TEntity : BaseEntity where T : ViewModel
        {
            var list = db.Set<TEntity>().AsNoTracking();
            if (where != null)
            {
                list = list.Where(where);
            }
            if (orders != null && orders.Count > 0)
            {
                IOrderedQueryable<TEntity> orderList = null;
                var order1 = orders[0];
                if (order1.IsAsc)
                {
                    orderList = list.OrderBy(order1.Order);
                }
                else
                {
                    orderList = list.OrderByDescending(order1.Order);
                }
                foreach (var order in orders.Skip(1).ToList())
                {
                    if (order.IsAsc)
                    {
                        orderList = orderList.ThenBy(order.Order);
                    }
                    else
                    {
                        orderList = orderList.ThenByDescending(order.Order);
                    }
                }
                list = orderList;
            }
            else if (where != null)
            {
                list = list.OrderByDescending(p => p.Id);
            }
            var user = list.ProjectToType<T>().FirstOrDefault();
            return user;
        }
        /// <summary>
        /// 根据条件获得model
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="db"></param>

        /// <param name="where"></param>
        /// <returns></returns>
        public static async Task<T> GetModelAsync<TEntity, T>(this DbContext db, Expression<Func<TEntity, bool>> where = null, List<ParaOrder<TEntity>> orders = null) where TEntity : BaseEntity where T : ViewModel
        {
            var list = db.Set<TEntity>().AsNoTracking();
            if (where != null)
            {
                list = list.Where(where);
            }
            if (orders != null && orders.Count > 0)
            {
                IOrderedQueryable<TEntity> orderList = null;
                var order1 = orders[0];
                if (order1.IsAsc)
                {
                    orderList = list.OrderBy(order1.Order);
                }
                else
                {
                    orderList = list.OrderByDescending(order1.Order);
                }
                foreach (var order in orders.Skip(1).ToList())
                {
                    if (order.IsAsc)
                    {
                        orderList = orderList.ThenBy(order.Order);
                    }
                    else
                    {
                        orderList = orderList.ThenByDescending(order.Order);
                    }
                }
                list = orderList;
            }
            else if (where != null)
            {
                list = list.OrderByDescending(p => p.Id);
            }
            var user = await list.ProjectToType<T>().FirstOrDefaultAsync();
            return user;
        }

        /// <summary>
        /// 分页获得信息
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="db"></param>

        /// <param name="where"></param>
        /// <param name="paraPage"></param>
        /// <param name="orders"></param>
        /// <param name="hasTotal"></param>
        /// <returns></returns>
        public static ReturnList<T> GetListByPage<TEntity, T>(this DbContext db, Expression<Func<TEntity, bool>> where = null, ParaPage paraPage = null, List<ParaOrder<TEntity>> orders = null, bool hasTotal = false) where TEntity : BaseEntity where T : ViewModel
        {
            var list = db.Set<TEntity>().AsNoTracking();
            if (where != null)
            {
                list = list.Where(where);
            }
            int total = 0;
            if (paraPage != null && paraPage.TakeNum > 0 && hasTotal)
            {
                total = list.Count();
            }
            if (orders != null && orders.Count > 0)
            {
                IOrderedQueryable<TEntity> orderList = null;
                var order1 = orders[0];
                if (order1.IsAsc)
                {
                    orderList = list.OrderBy(order1.Order);
                }
                else
                {
                    orderList = list.OrderByDescending(order1.Order);
                }
                foreach (var order in orders.Skip(1).ToList())
                {
                    if (order.IsAsc)
                    {
                        orderList = orderList.ThenBy(order.Order);
                    }
                    else
                    {
                        orderList = orderList.ThenByDescending(order.Order);
                    }
                }
                list = orderList;
            }
            else
            {
                list = list.OrderByDescending(p => p.Id);
            }
            if (paraPage != null && paraPage.TakeNum > 0)
            {
                list = list.Skip(paraPage.SkipNum).Take(paraPage.TakeNum);
            }
            var dataList = list.ProjectToType<T>().ToList();
            return new ReturnList<T>() { List = dataList, Total = total };
        }
        /// <summary>
        /// 分页获得信息
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="db"></param>

        /// <param name="where"></param>
        /// <param name="paraPage"></param>
        /// <param name="orders"></param>
        /// <param name="hasTotal"></param>
        /// <returns></returns>
        public static async Task<ReturnList<T>> GetListByPageAsync<TEntity, T>(this DbContext db, Expression<Func<TEntity, bool>> where = null, ParaPage paraPage = null, List<ParaOrder<TEntity>> orders = null, bool hasTotal = false) where TEntity : BaseEntity where T : ViewModel
        {
            var list = db.Set<TEntity>().AsNoTracking();
            if (where != null)
            {
                list = list.Where(where);
            }
            int total = 0;
            if (paraPage != null && paraPage.TakeNum > 0 && hasTotal)
            {
                total = await list.CountAsync();
            }
            if (orders != null && orders.Count > 0)
            {
                IOrderedQueryable<TEntity> orderList = null;
                var order1 = orders[0];
                if (order1.IsAsc)
                {
                    orderList = list.OrderBy(order1.Order);
                }
                else
                {
                    orderList = list.OrderByDescending(order1.Order);
                }
                foreach (var order in orders.Skip(1).ToList())
                {
                    if (order.IsAsc)
                    {
                        orderList = orderList.ThenBy(order.Order);
                    }
                    else
                    {
                        orderList = orderList.ThenByDescending(order.Order);
                    }
                }
                list = orderList;
            }
            else
            {
                list = list.OrderByDescending(p => p.Id);
            }
            if (paraPage != null && paraPage.TakeNum > 0)
            {
                list = list.Skip(paraPage.SkipNum).Take(paraPage.TakeNum);
            }
            var dataList = await list.ProjectToType<T>().ToListAsync();
            return new ReturnList<T>() { List = dataList, Total = total };
        }
        /// <summary>
        /// 分页获得信息（如果条件中出现or 改为调用此方法，把or拆成多个条件）
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="db"></param>

        /// <param name="whereList"></param>
        /// <param name="paraPage"></param>
        /// <param name="orders"></param>
        /// <param name="hasTotal"></param>
        /// <param name="isOnly">是否保证数据唯一（去重）</param>
        /// <returns></returns>
        public static ReturnList<T> GetUnionListByPage<TEntity, T>(this DbContext db, List<Expression<Func<TEntity, bool>>> whereList, ParaPage paraPage = null, List<ParaOrder<TEntity>> orders = null, bool hasTotal = false, bool isOnly = true) where TEntity : BaseEntity where T : ViewModel
        {
            var returnList = new ReturnList<T>();
            Expression<Func<TEntity, bool>> where = null;
            if (whereList == null || whereList.Count == 1)
            {
                if (whereList != null)
                {
                    where = whereList[0];
                }
                return db.GetListByPage<TEntity, T>(where, paraPage, orders, hasTotal);
            }
            IQueryable<TEntity> list = db.Set<TEntity>().AsNoTracking().Where(whereList[0]);
            IQueryable<int> listCount = db.Set<TEntity>().AsNoTracking().Where(whereList[0]).Select(p => p.Id);
            foreach (var item in whereList.Skip(1).ToList())
            {
                list = list.Union(db.Set<TEntity>().AsNoTracking().Where(item));
                listCount = listCount.Union(db.Set<TEntity>().AsNoTracking().Where(item).Select(p => p.Id));
            }
            int total = 0;
            if (isOnly)
            {
                list = list.Distinct();
            }
            if (paraPage != null && paraPage.TakeNum > 0 && hasTotal)
            {
                total = listCount.Count();
            }
            if (orders != null && orders.Count > 0)
            {
                IOrderedQueryable<TEntity> orderList = null;
                var order1 = orders[0];
                if (order1.IsAsc)
                {
                    orderList = list.OrderBy(order1.Order);
                }
                else
                {
                    orderList = list.OrderByDescending(order1.Order);
                }
                foreach (var order in orders.Skip(1).ToList())
                {
                    if (order.IsAsc)
                    {
                        orderList = orderList.ThenBy(order.Order);
                    }
                    else
                    {
                        orderList = orderList.ThenByDescending(order.Order);
                    }
                }
                list = orderList;
            }
            else
            {
                list = list.OrderByDescending(p => p.Id);
            }
            if (paraPage != null && paraPage.TakeNum > 0)
            {
                list = list.Skip(paraPage.SkipNum).Take(paraPage.TakeNum);
            }
            var dataList = list.ProjectToType<T>().ToList();
            returnList = new ReturnList<T>() { List = dataList, Total = total };
            return returnList;
        }
        /// <summary>
        /// 分页获得信息（如果条件中出现or 改为调用此方法，把or拆成多个条件）
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="db"></param>

        /// <param name="whereList"></param>
        /// <param name="paraPage"></param>
        /// <param name="orders"></param>
        /// <param name="hasTotal"></param>
        /// <param name="isOnly">是否保证数据唯一（去重）</param>
        /// <returns></returns>
        public static async Task<ReturnList<T>> GetUnionListByPageAsync<TEntity, T>(this DbContext db, List<Expression<Func<TEntity, bool>>> whereList, ParaPage paraPage = null, List<ParaOrder<TEntity>> orders = null, bool hasTotal = false, bool isOnly = true) where TEntity : BaseEntity where T : ViewModel
        {
            var returnList = new ReturnList<T>();
            Expression<Func<TEntity, bool>> where = null;
            if (whereList == null || whereList.Count == 1)
            {
                if (whereList != null)
                {
                    where = whereList[0];
                }
                return await db.GetListByPageAsync<TEntity, T>(where, paraPage, orders, hasTotal);
            }
            IQueryable<TEntity> list = db.Set<TEntity>().AsNoTracking().Where(whereList[0]);
            IQueryable<int> listCount = db.Set<TEntity>().AsNoTracking().Where(whereList[0]).Select(p => p.Id);
            foreach (var item in whereList.Skip(1).ToList())
            {
                list = list.Union(db.Set<TEntity>().AsNoTracking().Where(item));
                listCount = listCount.Union(db.Set<TEntity>().AsNoTracking().Where(item).Select(p => p.Id));
            }
            int total = 0;
            if (isOnly)
            {
                list = list.Distinct();
            }
            if (paraPage != null && paraPage.TakeNum > 0 && hasTotal)
            {
                total = await listCount.CountAsync();
            }
            if (orders != null && orders.Count > 0)
            {
                IOrderedQueryable<TEntity> orderList = null;
                var order1 = orders[0];
                if (order1.IsAsc)
                {
                    orderList = list.OrderBy(order1.Order);
                }
                else
                {
                    orderList = list.OrderByDescending(order1.Order);
                }
                foreach (var order in orders.Skip(1).ToList())
                {
                    if (order.IsAsc)
                    {
                        orderList = orderList.ThenBy(order.Order);
                    }
                    else
                    {
                        orderList = orderList.ThenByDescending(order.Order);
                    }
                }
                list = orderList;
            }
            else
            {
                list = list.OrderByDescending(p => p.Id);
            }
            if (paraPage != null && paraPage.TakeNum > 0)
            {
                list = list.Skip(paraPage.SkipNum).Take(paraPage.TakeNum);
            }
            var dataList = await list.ProjectToType<T>().ToListAsync();
            returnList = new ReturnList<T>() { List = dataList, Total = total };
            return returnList;
        }
        #endregion
    }
}
